# *-* coding:utf8 *-*
import json
import sys
import time
import os
import frida
from pathlib import Path
import signal
import threading
import platform
import time
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QWidget
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QHBoxLayout
from PyQt5.QtWidgets import QVBoxLayout
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QTextEdit
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtWidgets import QLabel
from PyQt5.QtWidgets import QLineEdit
from PyQt5.QtWidgets import QDialog
from PyQt5.QtWidgets import QListView
from PyQt5.QtCore import QThread
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import QDateTime
from PyQt5.QtCore import QStringListModel
import analysis


def kill_self():
    os.kill(os.getpid(), signal.SIGTERM)


def exec_cmd(cmd):
    input = os.popen(cmd)
    text = input.read()
    input.close()
    return text


def get_system():
    print(platform.platform())


class UpdateThread(QThread):
    update_data = pyqtSignal()

    def run(self):
        time.sleep(5)
        self.update_data.emit()


class PackageDlg(QDialog):
    list_view = None
    name = None
    q_list = None

    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.setWindowTitle('包名称')
        self.setGeometry(1000, 400, 300, 500)

        v_box = QVBoxLayout()
        h_box_list = QHBoxLayout()
        self.list_view = QListView()
        self.list_view.clicked.connect(self.clicked_list)

        h_box_list.addWidget(self.list_view)
        v_box.addLayout(h_box_list)

        h_box_button = QHBoxLayout()
        refresh = QPushButton('刷新')
        refresh.clicked.connect(self.refresh)
        define = QPushButton('确定')
        define.clicked.connect(self.define)

        buttons = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok |
                                             QtWidgets.QDialogButtonBox.Cancel)

        buttons.button(QtWidgets.QDialogButtonBox.Ok).setText('确定')
        buttons.button(QtWidgets.QDialogButtonBox.Cancel).setText('取消')

        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        h_box_button.addWidget(buttons)
        v_box.addLayout(h_box_button)

        self.setLayout(v_box)
        self.update_list_view()

    def update_list_view(self):
        text = exec_cmd('adb shell pm list packages')
        lines = text.split('\n')

        slm = QStringListModel()
        self.q_list = list()
        for item in lines:
            self.q_list.append(item[8:])

        slm.setStringList(self.q_list)
        self.list_view.setModel(slm)
        self.list_view.show()

    def refresh(self):
        self.update_list_view()

    def define(self):
        self.close()

    def get_package_name(self):
        return self.name

    def clicked_list(self, q_model_index):
        self.name = self.q_list[q_model_index.row()]


class MainWin(QMainWindow):
    text = None
    result = None
    package_name_line = None
    script = None

    def __init__(self):
        super(MainWin, self).__init__()
        self.init_ui()

    def init_ui(self):

        h_box = QHBoxLayout()
        h_box.stretch(7)

        package_label = QLabel("包名:")
        self.package_name_line = QLineEdit()

        select = QPushButton("选择包名")
        select.clicked.connect(self.get_packages)

        h_box.addWidget(package_label, 0)
        h_box.addWidget(self.package_name_line, 5)
        h_box.addWidget(select, 0)

        h_box_btn = QHBoxLayout()

        start_analysis = QPushButton("开始检测")
        start_analysis.clicked.connect(self.start_analysis)
        h_box_btn.addWidget(start_analysis)

        result = QPushButton("结果处理")
        result.clicked.connect(self.show_result)
        h_box_btn.addWidget(result)

        self.text = QTextEdit()
        self.text.setFontFamily('Consolas')
        self.text.setFontPointSize(14)

        self.result = QTextEdit()
        self.result.setFontFamily('Consolas')
        self.result.setFontPointSize(14)
        h_box_text = QVBoxLayout()
        h_box_text.addWidget(self.text)
        h_box_text.addWidget(self.result)

        v_box = QVBoxLayout()
        v_box.addLayout(h_box)
        v_box.addLayout(h_box_btn)
        v_box.addLayout(h_box_text)

        widget = QWidget()
        widget.setLayout(v_box)

        self.setCentralWidget(widget)
        self.setGeometry(900, 300, 800, 700)
        self.setWindowTitle('Buttons')
        self.setWindowTitle('App动态权限检测')
        self.show()

    def closeEvent(self, event):
        reply = QMessageBox.question(self, '确认', '确认退出吗', QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

    def start_analysis(self):
        if self.package_name_line.text() == '':
            return
        self.text.clear()
        thread = threading.Thread(target=self.spawn_app, args={self.package_name_line.text()})
        thread.start()

        # sub_thread = UpdateThread()
        # sub_thread.update_data.connect(self.show_result)
        # sub_thread.start()

    def update_text(self, msg):
        self.text.append(msg)

    def get_packages(self):
        dlg = PackageDlg()
        if dlg.exec_():
            name = dlg.get_package_name()
            self.package_name_line.setText(name)

    def show_result(self):
        self.result.clear()
        result = analysis.analysis()
        for item in result:
            self.result.append(item)

    def spawn_app(self, package_name):
        try:
            print(package_name)
            file = open('message.txt', 'w')
            file.close()
            with open(Path(__file__).resolve().parent.joinpath("./script.js"), encoding="utf-8") as f:
                script = f.read()
            process = frida.get_remote_device()
            pid = process.spawn(package_name)  # com.hx.hxsocket  'com.tencent.mobileqq'
            session = process.attach(pid)
            self.script = session.create_script(script)
            self.script.on('message', self.on_message)
            print('[*] Start Hook App')
            self.script.load()
            process.resume(pid)
        except Exception as e:
            ex.update_text(str(e))

    @staticmethod
    def on_message(message, data):
        if message['type'] == 'send':
            text = message['payload']
            insert_msg(text)
            file = open('message.txt', 'a+')
            file.write(text)
            file.write('\n')
            file.close()

        elif message['type'] == 'error':
            print(message)
            kill_self()


def insert_msg(msg):
    message = json.loads(msg)
    name = message['name']
    ex.update_text('调用函数: ' + name)
    ex.update_text('函数堆栈: ')
    content = message['content']
    for item in content:
        ex.update_text('         ' + item)
    ex.update_text('调用sdk信息:' + analysis.has_sdk(content))


if __name__ == '__main__':
    try:
        app = QApplication(sys.argv)
        ex = MainWin()
        sys.exit(app.exec_())
    except Exception as e:
        print(e)


    # process = frida.get_remote_device()
    # pid = process.spawn('com.tencent.mobileqq') #com.hx.hxsocket
    # session = process.attach(pid)
    # script = session.create_script(script)
    # script.on('message', on_message)
    # print('[*] Start Hook App')
    # script.load()
    # process.resume(pid)
    # sys.stdin.read()

    # process = frida.get_remote_device().attach('com.tencent.mm')
    # script = process.create_script(script)
    # script.on('message', on_message)
    # print('[*] Start Hook App')
    # script.load()
    # sys.stdin.read()


